/* save 20/12/05(土) 22:05:47 今回は 次回は 頂点の位置を始点からの相対高さで指定したい。 aがいくつだったら頂点のyを指定の値にできるか。 */ class App_20201206183001 { constructor( canvasId ) { this.cc = document.getElementById( canvasId ).getContext( "2d" ); let cc = this.cc; cc.translate( cc.canvas.width / 2, cc.canvas.height /2 ); cc.scale( 1, -1 ); cc.tmp = { circle : function( x, y, r, strokeStyle, fillStyle ) { cc.beginPath(); cc.arc( x, y, r, 0, 6.28 ); cc.closePath(); if( typeof fillStyle !== "undefined" && fillStyle != null ) { cc.fillStyle = fillStyle; cc.fill(); } if( typeof strokeStyle !== "undefined" && strokeStyle != null ) { cc.strokeStyle = strokeStyle; cc.stroke(); } }, } let div = document.createElement( "div" ); div.innerHtml = "test"; console.log( this.cc.canvas.nextElementSibling ); this.cc.canvas.parentNode.insertBefore( div, this.cc.canvas.nextElementSibling ); this.graphPaper = new GraphPaper_20201206183001( function( x ) { return x * x } ); this.draw( this.cc ); this.anms = new Array(); this.anms.push( { object : this.graphPaper, propertyName : "sy", sx : -100, ex : 100, step : 5, dir : -1, frame : function() { this.object[ this.propertyName ] += this.step * this.dir; //check. if( this.dir > 0 && this.object[ this.propertyName ] >= this.ex || this.dir < 0 && this.object[ this.propertyName ] <= this.sx ) { this.dir *= -1; } }, } ); this.anms.push( { object : this.graphPaper, propertyName : "ey", sx : -100, ex : 100, step : 5, dir : 1, frame : function() { this.object[ this.propertyName ] += this.step * this.dir; //check. if( this.dir > 0 && this.object[ this.propertyName ] >= this.ex || this.dir < 0 && this.object[ this.propertyName ] <= this.sx ) { this.dir *= -1; } }, } ); this.anms.push( { object : this.graphPaper, propertyName : "sx", sx : -200, ex : 100, step : 5, dir : 1, frame : function() { this.object[ this.propertyName ] += this.step * this.dir; //check. if( this.dir > 0 && this.object[ this.propertyName ] >= this.ex || this.dir < 0 && this.object[ this.propertyName ] <= this.sx ) { this.dir *= -1; } }, } ); this.anms.push( { object : this.graphPaper, propertyName : "ex", sx : -100, ex : 200, step : 5, dir : -1, frame : function() { this.object[ this.propertyName ] += this.step * this.dir; //check. if( this.dir > 0 && this.object[ this.propertyName ] >= this.ex || this.dir < 0 && this.object[ this.propertyName ] <= this.sx ) { this.dir *= -1; } }, } ); }//constructor start() { this.runtype = "key"; switch( this.runtype ) { case "key": this.keyfunc = function( e ) { switch( e.which ) { case 32: this.frame(); break; case 65: //a this.graphPaper.a += 0.001; this.draw( this.cc ); break; case 90: //z this.graphPaper.a -= 0.001; this.draw( this.cc ); break; default: console.log( e.which ); return true; } e.stopPropagation(); e.preventDefault(); return false; }.bind( this ); addEventListener( "keydown", this.keyfunc ); break; case "timer": default: setInterval( this.frame.bind( this ), 100 ); }//switch } stop() { switch( this.runtype ) { case "key": removeEventListener( "keydown", this.keyfunc ); break; } } frame() { this.anms.map( anm => anm.frame() ); this.draw( this.cc ); } draw( cc ) { this.graphPaper.draw( cc ); //原点 if( 0 ) { cc.tmp.circle( 0, 0, 4, null, "red" ); cc.save(); cc.scale( 1, -1 ); cc.fillText( "原点", 12, 0 ); cc.restore(); } } } class GraphPaper_20201206183001 { constructor() { this.f = null; this.sx = -100; this.sy = 10; this.ex = 100; this.ey = 50; this.axisX = 1; //放物線の頂点のx座標 this.numberOfPoints = 100; this.adjustY = null; this.a = -0.01; } //sxからexまでをnumberOfPoints分割したとき、 //分割のindex番目の、グラフ上のpx,pyを求める。 setIndex( index ) { this.index = index; this.px = this.sx + index * this.step; this.py = this.f( this.px ); } //放物線の式を更新 update( a, sx, sy, ex, ey ) { /* https://naop.jp/ensyu/1/kai3_2_3.html */ //y=ax^2+bx+c //sx,syを代入 //sy=asx^2+bsx+c //cについて解いて //c=sy - asx^2 - bsx ...[1] //次にex,eyを代入 //ey=aex^2+bex+c //[1]を代入 //ey=aex^2+bex+(sy - asx^2 - bsx) //bについて解いて //b = ( ey - aex^2 -sy + asx^2 ) / (ex - sx) let b = ( ey - a * Math.pow( ex, 2 ) - sy + a * Math.pow( sx, 2 ) ) / ( ex - sx ); let c = sy - a * Math.pow( sx, 2 ) - a * sx; this.f = function( x ) { return a * Math.pow( x, 2 ) + b * x + c; } //sxからexまでをnumberOfPoints分割するときの間隔 this.step = ( this.ex - this.sx ) / this.numberOfPoints; //グラフの位置調整 this.setIndex( 0 ); this.adjustY = this.sy - this.py; //参考値 this.testY = Math.max( sy, ey ) + 50; } draw( cc ) { //画面クリア cc.clearRect( -cc.canvas.width / 2, -cc.canvas.height / 2, cc.canvas.width, cc.canvas.height ); //放物線の式を更新 this.update( this.a, this.sx, this.sy, this.ex, this.ey ); //放物線を描く for( let i = 0; i <= this.numberOfPoints; i++ ) { this.setIndex( i ); let y = this.py + this.adjustY; cc.tmp.circle( this.px, y, 2, null, "blue" ); } cc.fillStyle = "black"; //始点 cc.tmp.circle( this.sx, this.sy, 8, "blue" ); cc.save(); cc.translate( this.sx + 12, this.sy ); cc.scale( 1, -1 ); cc.fillText( "始点", 0, 0 ); cc.restore(); //終点 cc.tmp.circle( this.ex, this.ey, 8, "red" ); cc.save(); cc.translate( this.ex + 12, this.ey ); cc.scale( 1, -1 ); cc.fillText( "終点", 0, 0 ); cc.restore(); //参考値 if( 1 ) { cc.fillStyle = "red"; cc.fillRect( -cc.canvas.width / 2, this.testY, cc.canvas.width, 1 ); cc.save(); cc.translate( -cc.canvas.width / 2 + 16, this.testY ); cc.scale( 1, -1 ); cc.fillText( "この高さに放物線の頂点を合わせたい。", 0, -3 ); cc.restore(); } } }